package validator

import (
	"database/sql"
	"database/sql/driver"
	"github.com/Sir-yuChen/funAnalyse/global"
	"github.com/Sir-yuChen/funAnalyse/model"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/locales/en"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	enTranslations "github.com/go-playground/validator/v10/translations/en"
	zhTranslations "github.com/go-playground/validator/v10/translations/zh"
	"os"
	"reflect"
	"strings"
)

var (
	trans ut.Translator
)

// InitTrans 初始化翻译器
func InitTrans(locale string) {
	//修改gin框架中的Validator属性，实现自定制
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		// 注册一个获取json tag的自定义方法
		v.RegisterTagNameFunc(func(fld reflect.StructField) string {
			label := strings.SplitN(fld.Tag.Get("label"), ",", 2)[0]
			if label == "-" || label == "" {
				label = strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
			}
			return label
		})

		zhT := zh.New() //中文翻译器
		enT := en.New() //英文翻译器

		// 第一个参数是备用（fallback）的语言环境
		// 后面的参数是应该支持的语言环境（支持多个）
		uni := ut.New(zhT, zhT, enT) // 万能翻译器，保存所有的语言环境和翻译数据

		// locale 通常取决于 http 请求头的 'Accept-Language'
		var ok bool
		// 也可以使用 uni.FindTranslator(...) 传入多个locale进行查找
		trans, ok = uni.GetTranslator(locale)
		if !ok {
			global.GVA_LOG.Error("指定找到翻译器异常！！")
			os.Exit(-1)
		}

		// register all sql.Null* types to use the ValidateValuer CustomTypeFunc
		v.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullInt32{}, sql.NullBool{}, sql.NullFloat64{})
		// 注意！因为这里会使用到trans实例
		// 所以这一步注册要放到trans初始化的后面
		// 添加额外翻译
		AddTranslation(&v, trans)
		//自定义验证方法
		AddValidationMethod(&v)
		// 注册翻译器
		switch locale {
		case "en":
			enTranslations.RegisterDefaultTranslations(v, trans)
		case "zh":
			zhTranslations.RegisterDefaultTranslations(v, trans)
		default:
			zhTranslations.RegisterDefaultTranslations(v, trans)
		}
		global.GVA_Trans = trans
		return
	}
	return
}

// AddTranslation 自定义翻译器
func AddTranslation(v **validator.Validate, translator ut.Translator) {
	_ = (*v).RegisterTranslation("required", translator, registerTranslator("required", "{0}必填项[自定义翻译器]"), translate)
	_ = (*v).RegisterTranslation("checkPhone", translator, registerTranslator("checkPhone", "{0}校验不通过[自定义翻译器]"), translate)
	_ = (*v).RegisterTranslation("oneof", translator, registerTranslator("oneof", "{0}校验不通过[自定义翻译器]"), translate)
}

// AddValidationMethod 注册tag验证器
func AddValidationMethod(v **validator.Validate) {
	metod := NewValidationMetod()
	_ = (*v).RegisterValidation("checkPhone", metod.CheckPhoneMetod)
}

// registerTranslator 为自定义字段添加翻译功能
func registerTranslator(tag string, msg string) validator.RegisterTranslationsFunc {
	return func(trans ut.Translator) error {
		if err := trans.Add(tag, msg, false); err != nil {
			return err
		}
		return nil
	}
}

// translate 自定义字段的翻译方法
func translate(trans ut.Translator, fe validator.FieldError) string {
	msg, err := trans.T(fe.Tag(), fe.Field())
	if err != nil {
		panic(fe.(error).Error())
	}
	return msg
}

// ValidateValuer implements validator.CustomTypeFunc 自定义校验规则
func ValidateValuer(field reflect.Value) interface{} {
	if valuer, ok := field.Interface().(driver.Valuer); ok {
		val, err := valuer.Value()
		if err == nil {
			return val
		}
	}
	//spec.LocalTime 类型的自定义校验规则
	if field.Type() == reflect.TypeOf(model.LocalTime{}) {
		timeStr := field.Interface().(model.LocalTime).String()
		// 0001-01-01 00:00:00 是 go 中 time.Time 类型的空值
		// 这里返回 Nil 则会被 validator 判定为空值，而无法通过 `binding:"required"` 规则
		if timeStr == "0001-01-01 00:00:00" {
			return nil
		}
		return timeStr
	}
	return nil
}
